<?php
declare (strict_types = 1);

namespace app\im\controller;

use app\im\service\Ws;
use Swoole\WebSocket\Frame;
use Swoole\Timer;
use think\swoole\Websocket;
use think\swoole\websocket\Room;
use think\Request;
class Chat
{

    /**
     * 当前应用id
     * @var int
     */
    protected int $appid = 1;//appid<>app_id
    public function index(Request $request)
    {
        //鉴权验证
        $access_token = $request->get('access_token');
        // 校验失败则阻止升级为 WebSocket
        if (!$access_token || !Auth::checkToken($access_token)) {
            return response('Forbidden', 403);
        }
        $this->appid = Auth::checkToken($access_token);

        return \think\swoole\helper\websocket()
            ->onOpen(function ($request, \think\swoole\Websocket $websocket,Room $room) {
                // 连接建立
                try {

                    var_dump('建立连接成功');
                    $server = new \app\im\service\Chat($websocket,$this->appid);
                    // 把当前客户端加入全体房间
                    /**
                     * 房间名    含义说明
                     * system    系统广播（公告、通知等）
                     * public    所有用户通用的聊天室
                     * online_users    当前在线用户共享房间（做在线统计用）
                     * app_{appid}    代表某个具体应用下的用户
                     * role_{role}    例如 role_admin，可用于按角色群发消息
                     * region_{code}    区域、城市或国家房间，如 region_cn_sh
                     * group_{gid}    群聊房间，如微信群组
                     * device_{type}    客户端类型，如 device_web, device_ios
                     * lang_{lang}    语言分组，如 lang_zh, lang_en
                     */
                    $rooms = ['system','notice','online_users'];
                    foreach ($rooms as $room_name){
                        $websocket->join($this->appid."_".$room_name);
                    }

                    //sass级别频道
                    $websocket->join(['system']);

                    // 每隔 30 秒向客户端发送自定义 ping 消息
                    Timer::tick(30000, function () use ($websocket,$server) {
                        if ($websocket->isEstablished()) {
                            $server->sendPing();
                        }
                    });

                }catch (\Exception $e){
                    var_dump('建立连接失败'.$e->getMessage());
                    // 主动断开连接
                    $websocket->close();
                    return;
                }

            })
            ->onMessage(function (Websocket $websocket, Frame $frame,Room $room) {
                $server = new \app\im\service\Chat($websocket,$this->appid);
                $data = json_decode($frame->data, true);
                if(!isset($data['type'])){
                    var_dump('消息内容格式错误');
                    $server->error('error','消息内容格式错误');
                    // 主动断开连接
                    $websocket->close();
                    return;
                }
                //消息分发
                $this->dispatch($websocket,$room,$data);


            })->onPong(function (Websocket $websocket, Frame $frame) {
                var_dump('心跳pong');
            })
            ->onClose(function (Websocket $websocket) {
                // 连接关闭
                var_dump('关闭连接');
                $fd = $websocket->getSender();
                var_dump('当前$fd 为'.$fd.'已关闭连接');
            });
    }

    //消息分发
    public function dispatch(Websocket $websocket, Room $room,$data)
    {
        $type = $data['type'];
        $server = new \app\im\service\Chat($websocket,$this->appid);
        $ws = new Ws($websocket,$room,$this->appid);
        switch ($type){
            case 'bind':
                //验证参数
                if(!isset($data['data']['checkType'])){
                    $data['data']['checkType'] = 'token';
                }
                if(!in_array($data['data']['checkType'],['token','password'])){
                    $server->error('bind','用户绑定失败，请检查checkType参数');
                    // 主动断开连接
                    $websocket->close();
                    break;
                }
                $res = Auth::checkUserLogin($data['data'],$this->appid);
                if($res['code']==0){
                    $server->error('bind',$res['msg']);
                    // 主动断开连接
                    $websocket->close();
                    break;
                }
                var_dump('验证参数成功'.$res['data']);
                //绑定用户
                $server->bindUser($res['data']);
                break;
            case 'refreshToken':
                $res = Auth::refreshUserToken($data['data'],$this->appid);
                if($res['code']==0){
                    $server->error('refreshToken',$res['msg']);
                    // 主动断开连接
                    $websocket->close();
                    break;
                }
                $server->refreshToken($res['data']['user_id'],$res['data']);
                break;
            case 'chat':
                //验证用户是否绑定
                if(!$ws->checkUserLogin()){
                    $server->error('chat','用户未绑定，请先绑定');
                    // 主动断开连接
                    $websocket->close();
                    break;
                }
                var_dump($data);
                $websocket->emit('chat',$data['msg']);
                break;
            case 'pong':
                break;
        }
    }
}
